# 学习数据访问, 所有程序都在该py文件中
import os
import click

from flask import Flask, flash, redirect, render_template, url_for, request, send_from_directory, abort
from flask_sqlalchemy import SQLAlchemy
# 导入表单
from flask_wtf import FlaskForm
from wtforms import TextAreaField, SubmitField
from wtforms.validators import DataRequired
from flask_ckeditor import CKEditorField
from flask_ckeditor import CKEditor, upload_fail, upload_success
from ckeditor_form import RichTextForm
from flask_wtf import CSRFProtect

# 根目录
basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)

db = SQLAlchemy(app)

app.secret_key = 'a key ...'
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv(
    'DATABASE_URL', 'sqlite:////'+os.path.join(app.root_path, 'data.db'))
app.config['CKEDITOR_PKG_TYPE'] = 'standard'  # basic, standard, full
app.config['CKEDITOR_SERVE_LOCAL'] = True
app.config['CKEDITOR_FILE_UPLOADER'] = 'upload'
app.config['CKEDITOR_ENABLE_CSRF'] = True  # 不使用CSRF保护，可以注释本句
app.config['UPLOADED_PATH'] = os.path.join(basedir, 'uploads/ckeditor')

ckeditor = CKEditor(app)
csrf = CSRFProtect(app)  # 不使用CSRF保护，可以注释本句


# 创建一个Note模型
class Note(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)

    def __repr__(self):
        return '<Note: %r>' % self.body


# 一对多模型
class Author(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(70), unique=True)
    phone = db.Column(db.String(20))
    articles = db.relationship('Article')

    def __repr__(self):
        return '<Author: %r, %r>' % (self.name, self.phone)


class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50), index=True)
    body = db.Column(db.Text)
    author_id = db.Column(db.Integer, db.ForeignKey('author.id'))

    def __repr__(self):
        return '<Article: %r>' % self.title


@app.cli.command()
def init_db():
    # 创建一个初始化数据命令
    db.drop_all()
    db.create_all()
    click.echo('初始化数据库完成!!!')


# 表单 - 新建笔记
class NewNoteForm(FlaskForm):
    body = TextAreaField('笔记主体', validators=[DataRequired()])
    submit = SubmitField('保存')


# 表单 - 修改笔记
class EditNoteForm(FlaskForm):
    body = CKEditorField('笔记主体', validators=[DataRequired()])
    submit = SubmitField('修改')


# 表单 - 删除笔记
class DeleteNoteForm(FlaskForm):
    submit = SubmitField('删除')


# 视图函数------------------------------------

# 首页
@app.route('/')
def index():
    form = DeleteNoteForm()
    notes = Note.query.all()
    return render_template('db/index.html', notes=notes, form=form)


# 新建笔记
@app.route('/new', methods=['get', 'post'])
def new_note():
    form = NewNoteForm()
    if form.validate_on_submit():
        body = form.body.data
        note = Note(body=body)
        db.session.add(note)
        db.session.commit()
        flash('你的笔记已经存储成功!')
        return redirect(url_for('index'))
    return render_template('db/new_note.html', form=form)


# 修改笔记
@app.route('/edit/<int:note_id>', methods=['get', 'post'])
def edit_note(note_id):
    form = EditNoteForm()
    note = Note.query.get(note_id)
    if form.validate_on_submit():
        note.body = form.body.data
        db.session.commit()
        flash('笔记修改成功!')
        return redirect(url_for('index'))
    form.body.data = note.body
    return render_template('db/edit_note.html', form=form)


# 删除笔记
@app.route('/delete/<int:note_id>', methods=['post'])
def delete_note(note_id):
    form = DeleteNoteForm()
    if form.validate_on_submit():
        note = Note.query.get(note_id)
        db.session.delete(note)
        db.session.commit()
        flash('笔记删除成功!')
    else:
        abort(400)
    return redirect(url_for('index'))


@app.route('/files/<filename>')
def uploaded_files(filename):
    path = app.config['UPLOADED_PATH']
    return send_from_directory(path, filename)


@app.route('/upload', methods=['post'])
def upload():
    f = request.files.get('upload')
    extension = f.filename.split('.')[1].lower()
    if extension not in ['jpg', 'gif', 'png', 'jpeg']:
        return upload_fail(message='Image Only!')
    f.save(os.path.join(app.config['UPLOADED_PATH'], f.filename))
    url = url_for('uploaded_files', filename=f.filename)
    return upload_success(url=url)
